﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.XPath;
using ICSharpCode.SharpZipLib.Zip;

namespace Stanza.MSBuild.Tasks
{
    public delegate void WriteMessage( string messageText );

    public class Publish
    {
        private WriteMessage writeMsg;

        private void Msg( string msgFmt, params object[] argLst )
        {
            writeMsg( String.Format( msgFmt, argLst ) );
        }

        public Publish( WriteMessage writeMsg )
        {
            this.writeMsg = writeMsg;
        }

        public string ZipFileName { get; private set; }

        public void PublishSolution( string publishFileName )
        {
            Msg( "Beginning publishing process." );

            PublishInfo pubInfo = PublishInfo.Load( publishFileName );

            if( !File.Exists( pubInfo.SolutionFile ) )
                throw new FileNotFoundException( String.Concat( "Could not find: ", pubInfo.SolutionFile ), pubInfo.SolutionFile );

            SolutionFileHandler solutionFile = new SolutionFileHandler( pubInfo );
            solutionFile.ParseFile( pubInfo.SolutionFile );

            ZipFileName = pubInfo.ZipFile;
            if( File.Exists( pubInfo.ZipFile ) )
                File.Delete( pubInfo.ZipFile );
            string filePrefix = pubInfo.FileNamePrefix;

            using( FileStream writeStream = new FileStream( pubInfo.ZipFile, FileMode.Create, FileAccess.Write ) )
            using( ZipOutputStream zipOut = new ZipOutputStream( writeStream ) )
            {
                byte[] dataBuffer = new byte[10000];
                foreach( PublishFile pubFile in pubInfo.GetFilesToPublish() )
                {
                    FileInfo fileInfo = new FileInfo( pubFile.FileName );

                    string relativeFileName = PathTools.GetRelativePath( pubInfo.FilePath, pubFile.FileName );
                    Msg( "  {0}", relativeFileName );

                    using( FileStream readStream = new FileStream( pubFile.FileName, FileMode.Open, FileAccess.Read, FileShare.Read ) )
                    {
                        Stream dataStream = readStream;
                        if( pubFile.ModifyFile != null )
                            dataStream = pubFile.ModifyFile( readStream );

                        string zipEntryName = relativeFileName;
                        if( filePrefix != null )
                            zipEntryName = String.Concat( filePrefix, "/", zipEntryName );
                        zipEntryName = zipEntryName.Replace( "\\", "/" );

                        ZipEntry zipEntry = new ZipEntry( zipEntryName );
                        zipEntry.DateTime = fileInfo.LastWriteTime;
                        zipEntry.Size = dataStream.Length;
                        zipOut.PutNextEntry( zipEntry );

                        int readLen;
                        while( ( readLen = dataStream.Read( dataBuffer, 0, dataBuffer.Length ) ) != 0 )
                            zipOut.Write( dataBuffer, 0, readLen );
                    }
                }
                zipOut.Finish();
            }
            Msg( "Zip File created:" );
            Msg( "  {0}", pubInfo.ZipFile );

            Msg( "Finished publishing process." );
        }
    }
}
